package com.smc.hotfixdemo.utils;

import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class HookUtil {


    private static final String TAG = "HookUtil";


    public static void hookStartActivity_7(Context context)throws Exception{
        Object singleton = null;
        Class<?> amnClass = Class.forName("android.app.ActivityManagerNative");
        Field gDefaultField = amnClass.getDeclaredField("gDefault");
        gDefaultField.setAccessible(true);
        singleton = gDefaultField.get(null);

        Class<?> singletonClazz = Class.forName("android.util.Singleton");
        Field mInstanceField = singletonClazz.getDeclaredField("mInstance");
        mInstanceField.setAccessible(true);
        final Object mInstance = mInstanceField.get(singleton);

        Class<?> iActivityManagerClazz = Class.forName("android.app.IActivityManager");
        Object mInstanceProxy = Proxy.newProxyInstance(context.getClassLoader(),
                new Class[]{iActivityManagerClazz}, new InvocationHandler(){

                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        if("startActivity".equals(method.getName())){
                            int index = -1;
                            for( int i = 0; i < args.length; i++){
                                if(args[i] instanceof Intent){
                                    index = i;
                                    break;
                                }
                            }
                            if (index > 0){
                                Intent rawIntent = (Intent)args[index];
                                if (rawIntent.getBooleanExtra(Def.KEY_IS_MAIN, false) == true){
                                    Log.i(TAG, "replace plugin activity...");
                                    String strPackageName = rawIntent.getStringExtra(Def.KEY_PLUGIN_PACKAGE_NAME);
                                    String strClassName = rawIntent.getStringExtra(Def.KEY_PLUGIN_CLASS_NAME);
                                    Intent proxyIntent = new Intent();
                                    proxyIntent.setClassName(strPackageName, strClassName);
                                    proxyIntent.putExtra(Def.KEY_RAW_INTENT, rawIntent);
                                    proxyIntent.putExtra(Def.KEY_IS_PLUGIN, true);
                                    proxyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                    args[index] = proxyIntent;
                                }
                            }
                        }
                        return method.invoke(proxy, args);
                    }
                });
        mInstanceField.set(singleton, mInstanceProxy);
    }

    public static void hookStartActivity_8(Context context){
        try {
            ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
            Class clazz = activityManager.getClass();
            Field field_IActivityManagerSingleton = clazz.getDeclaredField("IActivityManagerSingleton");
            field_IActivityManagerSingleton.setAccessible(true);
            Object iActivityManagerSingleton =  field_IActivityManagerSingleton.get(null);
            Class clazz_singleton = iActivityManagerSingleton.getClass();
            Field field_mInstance = clazz_singleton.getDeclaredField("mInstance");
            field_mInstance.setAccessible(true);
            Object iActivityManager = field_mInstance.get(iActivityManagerSingleton);
            Class iterface = iActivityManager.getClass();
            Object newActivityManager = Proxy.newProxyInstance(context.getClassLoader(), new Class[]{iterface}, new InvocationHandler() {
                @Override
                public Object invoke(Object o, Method method, Object[] args) throws Throwable {


                    if ("startActivity".equals(method.getName())){
                        int index = -1;
                        for (int i = 0; i < args.length; i++){
                            Object obj = args[i];
                            if (obj instanceof Intent){
                                index = i;
                                break;
                            }
                        }
                        if (index > 0){
                            Intent rawIntent = (Intent)args[index];
                            if (rawIntent.getBooleanExtra(Def.KEY_IS_MAIN, false) == true){
                                Log.i(TAG, "replace plugin activity...");
                                String strPackageName = rawIntent.getStringExtra(Def.KEY_PLUGIN_PACKAGE_NAME);
                                String strClassName = rawIntent.getStringExtra(Def.KEY_PLUGIN_CLASS_NAME);
                                Intent proxyIntent = new Intent();
                                proxyIntent.setClassName(strPackageName, strClassName);
                                proxyIntent.putExtra(Def.KEY_RAW_INTENT, rawIntent);
                                proxyIntent.putExtra(Def.KEY_IS_PLUGIN, true);
                                proxyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                args[index] = proxyIntent;
                            }
                        }
                    }
                    return method.invoke(o, args);
                }
            });
            field_mInstance.set(iActivityManagerSingleton, newActivityManager);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static void hookHandler(Context context)throws Exception{

        Class<?> clazz = Class.forName("android.app.ActivityThread");
        Field activityThreadField = clazz.getDeclaredField("sCurrentActivityThread");
        activityThreadField.setAccessible(true);
        Object activityThread = activityThreadField.get(null);
        Field mHField = clazz.getDeclaredField("mH");
        mHField.setAccessible(true);
        final Handler mH = (Handler)mHField.get(activityThread);

        Handler.Callback callback = new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                switch(msg.what){
                    case 100:		//LAUNCH_ACTIVITY
                        Field intentField = null;
                        try{
                            intentField = msg.obj.getClass().getDeclaredField("intent");
                            intentField.setAccessible(true);
                            Intent proxyIntent = (Intent)intentField.get(msg.obj);
                            if (proxyIntent.getBooleanExtra(Def.KEY_IS_PLUGIN, false) == true){
                                Log.i(TAG, "replace to raw activity...");
                                Intent rawIntent = proxyIntent.getParcelableExtra(Def.KEY_RAW_INTENT);
                                if(rawIntent != null){
                                    intentField.set(msg.obj, rawIntent);
                                }
                            }
                        }catch(Exception e){
                            e.printStackTrace();
                        }
                        break;
                }
                return false;
            }
        };
        Class<?> handlerClazz = Class.forName("android.os.Handler");
        Field callBackField = handlerClazz.getDeclaredField("mCallback");
        callBackField.setAccessible(true);
        callBackField.set(mH, callback);
    }

}
